From db40172b64251d5837e454f351e6f9b267cc050f Mon Sep 17 00:00:00 2001 From: Safwat Halaby Date: Sun, 27 Sep 2015 20:20:03 +0300 Subject: Partial revert of #2446 --- src/Mobs/Monster.cpp | 45 ++++++++++++++++++++++++++++++++++++++++----- src/Mobs/Monster.h | 15 +++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index b28e94ec1..4d9b9ca06 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -78,6 +78,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A , m_IsFollowingPath(false) , m_PathfinderActivated(false) , m_GiveUpCounter(0) + , m_TicksSinceLastPathReset(1000) , m_LastGroundHeight(POSY_TOINT) , m_JumpCoolDown(0) , m_IdleInterval(0) @@ -128,6 +129,11 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) { return false; } + if (m_TicksSinceLastPathReset < 1000) + { + // No need to count beyond 1000. 1000 is arbitary here. + ++m_TicksSinceLastPathReset; + } if (ReachedFinalDestination()) { @@ -135,6 +141,26 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) return false; } + if ((m_FinalDestination - m_PathFinderDestination).Length() > 0.25) // if the distance between where we're going and where we should go is too big. + { + /* If we reached the last path waypoint, + Or if we haven't re-calculated for too long. + Interval is proportional to distance squared, and its minimum is 10. + (Recalculate lots when close, calculate rarely when far) */ + if ( + ((GetPosition() - m_PathFinderDestination).Length() < 0.25) || + ((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.4 * (m_FinalDestination - GetPosition()).SqrLength()))) + ) + { + /* Re-calculating is expensive when there's no path to target, and it results in mobs freezing very often as a result of always recalculating. + This is a workaround till we get better path recalculation. */ + if (!m_NoPathToTarget) + { + ResetPathFinding(); + } + } + } + if (m_Path == nullptr) { if (!EnsureProperDestination(a_Chunk)) @@ -143,16 +169,21 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) return false; } m_GiveUpCounter = 40; - m_Path = new cPath(a_Chunk, GetPosition(), m_FinalDestination, 20, GetWidth(), GetHeight()); + m_NoPathToTarget = false; + m_NoMoreWayPoints = false; + m_PathFinderDestination = m_FinalDestination; + m_Path = new cPath(a_Chunk, GetPosition(), m_PathFinderDestination, 20, GetWidth(), GetHeight()); } switch (m_Path->Step(a_Chunk)) { case ePathFinderStatus::NEARBY_FOUND: { - m_FinalDestination = m_Path->AcceptNearbyPath(); + m_NoPathToTarget = true; + m_PathFinderDestination = m_Path->AcceptNearbyPath(); break; } + case ePathFinderStatus::PATH_NOT_FOUND: { StopMovingToPosition(); // Try to calculate a path again. @@ -166,10 +197,9 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) } case ePathFinderStatus::PATH_FOUND: { - if ((--m_GiveUpCounter) == 0) + if (m_NoMoreWayPoints || (--m_GiveUpCounter == 0)) { - // Failed to reach a waypoint - that's a failure condition whichever point we're at - if (m_EMState == CHASING) + if (m_EMState == ATTACKING) { ResetPathFinding(); // Try to calculate a path again. // This results in mobs hanging around an unreachable target (player). @@ -188,6 +218,10 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition. } } + else + { + m_NoMoreWayPoints = true; + } m_IsFollowingPath = true; return true; @@ -379,6 +413,7 @@ void cMonster::StopMovingToPosition() void cMonster::ResetPathFinding(void) { + m_TicksSinceLastPathReset = 0; m_IsFollowingPath = false; if (m_Path != nullptr) { diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index f9b271bf9..22280110c 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -120,8 +120,8 @@ public: char GetAge (void) const { return m_Age; } void SetAge(char a_Age) { m_Age = a_Age; } // tolua_end - - + + // tolua_begin /** Returns true if the monster has a custom name. */ @@ -178,6 +178,7 @@ protected: /* If 0, will give up reaching the next m_NextWayPointPosition and will re-compute path. */ int m_GiveUpCounter; + int m_TicksSinceLastPathReset; /** Coordinates of the next position that should be reached */ Vector3d m_NextWayPointPosition; @@ -185,6 +186,16 @@ protected: /** Coordinates for the ultimate, final destination. */ Vector3d m_FinalDestination; + /** Coordinates for the ultimate, final destination last given to the pathfinder. */ + Vector3d m_PathFinderDestination; + + /** True if there's no path to target and we're walking to an approximated location. */ + bool m_NoPathToTarget; + + /** Whether The mob has finished their path, note that this does not imply reaching the destination, + the destination may sometimes differ from the current path. */ + bool m_NoMoreWayPoints; + /** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does) If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1 If current Y is solid, goes up to find first nonsolid block, and returns that. -- cgit v1.2.3